package org.xems.net
{
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	
	import org.xems.events.LoaderEvent;
	
	/**
	 * 
	 * @author qixiaowei
	 * 
	 */
	public class LoaderManager implements IEventDispatcher
	{
		private var loader:Loader;
		private var urlloader:URLLoader;
		private var _currentMission:LoaderMission = null;
		private var _queue:Vector.<LoaderMission>;
		
		private var dispatcher:EventDispatcher;
		public function LoaderManager()
		{
			dispatcher = new EventDispatcher(this);
			
			_queue = new Vector.<LoaderMission>();
			loader = new Loader();
			addListener(loader.contentLoaderInfo);
			
			urlloader = new URLLoader();
			addListener(urlloader);
		}
		
		public function addMission(mission:LoaderMission):void
		{
			if(getMissionIndex(mission) < 0){
				_queue.push(mission);
				loadNext();
			}
		}
		
		private function removeMission(mission:LoaderMission):void
		{
			var index:int = getMissionIndex(mission);
			_queue.splice(index, 1);
		}
		
		private function getMissionIndex(mission:LoaderMission):int
		{
			var len:uint = _queue.length;
			while(len-->0){
				var node:LoaderMission = _queue[len];
				if(node.name == mission.name && node.url == mission.url){
					return len;
				}
			}
			return -1;
		}
		
		private function loadNext():void
		{
			if(this.currentMission){
				return;
			}
			_currentMission = _queue[0];
			if(_currentMission.type == LoaderMission.LOAD_BYTES_TYPE){
				urlloader.load(new URLRequest(_currentMission.url));
				_currentMission.loader = urlloader;
			}else if(_currentMission.type == LoaderMission.LOAD_DISPLAY_TYPE){
				if(loader == null){
					loader = new Loader();
					addListener(loader.contentLoaderInfo);
				}
				loader.load(new URLRequest(_currentMission.url), _currentMission.loaderContext);
				_currentMission.loader = loader;
			}
		}
		
		private function addListener(dispatcher:IEventDispatcher):void
		{
			dispatcher.addEventListener(Event.COMPLETE, onLoadComplete);
			dispatcher.addEventListener(Event.OPEN, onLoadStart);
			dispatcher.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
			dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			dispatcher.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
		}
		
		private function removeListener(dispatcher:IEventDispatcher):void
		{
			dispatcher.removeEventListener(Event.COMPLETE, onLoadComplete);
			dispatcher.removeEventListener(Event.OPEN, onLoadStart);
			dispatcher.removeEventListener(ProgressEvent.PROGRESS, onLoadProgress);
			dispatcher.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			dispatcher.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
		}
		
		private function onIOError(event:IOErrorEvent):void
		{
			var evt:LoaderEvent = new LoaderEvent(LoaderEvent.LOAD_ERROR);
			evt.loaderMission = _currentMission;
			evt.value = event.text;
			dispatchEvent(evt);
		}
		
		private function onSecurityError(event:SecurityErrorEvent):void
		{
			var evt:LoaderEvent = new LoaderEvent(LoaderEvent.LOAD_ERROR);
			evt.loaderMission = _currentMission;
			evt.value = event.text;
			dispatchEvent(evt);
		}
		
		private function onLoadStart(event:Event):void
		{
			var evt:LoaderEvent = new LoaderEvent(LoaderEvent.LOAD_START);
			evt.loaderMission = _currentMission;
			dispatchEvent(evt);
		}
		
		private function onLoadProgress(event:ProgressEvent):void
		{
			_currentMission.bytesLoaded = event.bytesLoaded;
			_currentMission.bytesTotal = event.bytesTotal;
			
			var evt:LoaderEvent = new LoaderEvent(LoaderEvent.LOAD_PROGRESS);
			evt.loaderMission = _currentMission;
			dispatchEvent(evt);
		}
		
		private function onLoadComplete(event:Event):void
		{
			var completeMission:LoaderMission = _currentMission;
			completeMission.data = completeMission.type == LoaderMission.LOAD_BYTES_TYPE?urlloader.data:loader;
			
			removeMission(_currentMission);
			_currentMission = null;
			
			var evt:LoaderEvent = new LoaderEvent(LoaderEvent.LOAD_COMPLETE);
			evt.loaderMission = completeMission;
			if(completeMission.completeCallback != null){
				completeMission.completeCallback(evt.clone());
			}
			dispatchEvent(evt);
			
			if(_queue.length == 0){
				evt = new LoaderEvent(LoaderEvent.LOAD_ALL_COMPLETE);
				evt.loaderMission = completeMission;
				dispatchEvent(evt);
			}else{
				if(loader){
					removeListener(loader.contentLoaderInfo);
					loader = null;
				}
				
				loadNext();
			}
		}
		
		public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
		{
			dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}
		
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
		{
			dispatcher.removeEventListener(type, listener, useCapture);
		}
		
		public function dispatchEvent(event:Event):Boolean
		{
			return dispatcher.dispatchEvent(event);
		}
		
		public function hasEventListener(type:String):Boolean
		{
			return dispatcher.hasEventListener(type);
		}
		
		public function willTrigger(type:String):Boolean
		{
			return dispatcher.willTrigger(type);
		}

		/**
		 * 等待加载的对列
		 */
		public function get queue():Vector.<LoaderMission>
		{
			return _queue;
		}

		/**
		 * 当前加载任务
		 */
		public function get currentMission():LoaderMission
		{
			return _currentMission;
		}
	}
}